{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# CS 237 Spring 2021, HW 03 \n", "\n", "#### Due date: Friday February 19th at Midnight (1 minute after 11:59pm on 2/11) via Gradescope (6 hour grace period)\n", "\n", " Late policy: You may submit the homework up to 24 hours late for a 10% penalty. Hence, the late deadline is Saturday 2/20 at Midnight (with the same 6 hour grace period). \n", "\n", "#### General Instructions\n", "\n", "Please complete this notebook by filling in solutions where indicated. Be sure to \"Restart and Run All\" from the Kernel menu before submitting to Gradescope. \n", "\n", "There are 10 analytical problems and one extended programming problem (worth as much as two problems). An introductory video will be posted on YT for\n", "the analytical problems, and the programming problem will be covered Friday in lab. " ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "scrolled": false }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAASwAAAEWCAYAAADcnKq+AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjMsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+AADFEAAAbX0lEQVR4nO3deZhcVZ3G8e9LIOyyhRnIRkDiMEERMSzzuICCM0EgqICAIKtGHs2AgAIqoICMiLhiRKMgCIOEbSBgFBEBB2VJAggGBgmRJYQlAWSTLfCbP86pcFOp7qokfbtzOu/nefrpqruce+rWvW+dc6vqlCICM7MSrNDXFTAz65QDy8yK4cAys2I4sMysGA4sMyuGA8vMirHMBpakr0m6YAnXPUjSTd3M/7WkA1stK+kFSZssyXaXhKQfSzqhh8oanus/IN+/QdKneqLsXN6C/dabJH1d0jxJj/f2tvtCu+N3Ccvs9nyS9KCknXpym7ncEZJC0or5/lIdkz0aWPlBv5RPmick/VzSGj25jZ4QETtHxHldzFsjImYBSDpX0teXdDuV/fG8pL9L+pOkwyQt2O8RcVhEnNJhWd0eUBHxcK7/60ta58r2FjnAu9tvdZE0DDgaGBURG7SYv4OkN/IxV/37t96sZ2+StLKkb0h6OB9f90v6oiTVtL1zJb2a9+vTkq6VtFkd22qnjhbWbhGxBrAVsDVwfPMCSpbZ1l0P2y0i1gQ2Ak4DjgXO7umNNF7B+qGNgKci4slulpmTg7r6d3NvVbAPXALsCHwYWBP4JDAO+H6N2zw9n9dDgEep4RjuRG2hERGPAr8G3g4LmoKnSvoj8A9gE0mDJU3OqT1T0qebillF0qTcQrld0jsbMyQdJ+mBPO8eSR9tWleSzpT0rKT/k7RjZUaXzdLcfN1U0jhgP+CY/MpyVX4Vu6xp+TMlfa+D/fFsREwG9gYOlNTYLwtacZIGSbo6t8aelvS/klaQdD4wHLgq1+WYSlP7UEkPA79vbn5nb5V0W94PV0paN29rB0mzmx7Lg5J2kjQG+DKwd97en5v3W67X8ZIekvSkpF9IWivPa9TjwNwKmCfpK13tG0lr5fXn5vKOz+XvBFwLDM71OLfdfm4qdx9J05qmHSlpcr69sqQzch2fUOqer1rdP5KOzo/vMUkHd7OtgyXdm4/HWZI+U5nXbVmS1svnwXOSbgPe2s12dgT+HdgjIv4SEfMj4hZgf+BzkjbNy20s6cZcn2uBQU3lfDLv66e6e26aRcRLwMXAlpWyujwWupPPsxvzsTlP0qR269QWWEpN+Q8Dd1QmN14J1gQeAn4JzAYGA3sC/1UNFmB30qvJusCFwBWSVsrzHgDeB6wFnARcIGnDyrrbArNIT9RXgcsbJ2snImIi8N/kV5aI2A24ABgjae38GFckBdD5i1Hubfkxv6/F7KPzvPWBfyaFRkTEJ4GHya3XiDi9ss72wL8C/9HFJg8ADiHt4/nADzqo42+A/wIm5e29s8ViB+W/DwCbAGsAP2xa5r3Av5BaAydK+tcuNnkm6XncJD+eA4CDI+J3wM682YI6qF3dm0wG/kXSyMq0T5COJYBvAm8jnXybkloPJ1aW3SDXawhwKDBB0jpdbOtJYFfgLcDBwHclbdVhWROAl4ENSc/VId08pg8Bt0bEI9WJEXEr6dhpnD8XAtNJx/8pwIJrj5JGAWeRzsfBwHrA0G62uYCk1YF9gZmVyQfR/lho5RTgt8A6eftntluhjsC6QtLfgZuAG0kHfsO5ETEjIuaTnsD3AsdGxMsRcSfwM9JObJgeEZdGxGvAd4BVgO0AIuKSiJgTEW9ExCTgfmCbyrpPAt+LiNfy/PuAXZbmgUXEY8AfgL3ypDHAvIiYvphFzSGFcLPXSAftRrne/xvtv+z5tYh4Mb/ytXJ+fiV+ETgB+LjyRfmltB/wnYiYFREvAF8C9mlq3Z0UES9FxJ+BPwOLBF+uy97AlyLi+Yh4EPg2Cx8H7QzOrdLq3+oR8Q/gStIJRg6uzYDJkgR8GjgyIp6OiOdJx+o+lXJfA07Oz8UU4AVSAC8iIn4VEQ9EciPpRHxfu7Ly498DODE/j38BurtOOAh4rIt5jwGDJA0nXY45ISJeiYg/AFdVltsTuDoi/hARr5COize62SbAF/J5/TzpvK0+P50cC628RuryD84Z0PaNhjoC6yMRsXZEbBQRn206kaqvCoOBxoHS8BDpFWiR5SPiDd5sjSHpAEl3Ng5QUtez2ux9tOlkf6ix7lI6j9T8Jv/vuHVVMQR4usX0b5FeuX6buxXHdVDWI4sx/yFgJZq6B0tocC6vWvaKpJZhQ/VdvX+QXnmbDQIGtihrSItluzInH3PVvxfzvAvJgUVqXV2Rg2x9YDVgeuUY+k2e3vBUfnFt9xiQtLOkW5S68n8n9S6q+7mrstYn7bfm56kr80gvaq1smOcPBp6p7IPmMgez8Ln1IvBUN9sEOCMi1gZGAC+xcHB3ciy0cgwg4DZJMyR117IEev9jDdUAmQOsK2nNyrThpAt6DcMaN5Qu0g8F5kjaCPgpMB5YL+/Iv5AefMOQ/CpaLXvOUtS34QpgC6VrULuSuo0dk7Q16WRc5NUktzCOjohNgN2Aoypd5K5aWu1aYMMqt4eTXtXmAS+STthGvQaw8Mnartw5pFfHatnzgSfarNdsHm++0lbLerT14ovtt6RWx5ak4Gp0B+eRTrzNKyG3Vr6wvFgkrQxcBpwB/HM+Hqew8PHYlbmk/db8PHXld8C2+ZJLtQ7b5DJ+T2pprZO7b63KfIyFz63VSN3CtiLiYeAI4PuN630s4bEQEY9HxKcjYjDwGeBHjWtwXemzd+pyH/xPwDckrSJpC1LfvhoA75b0sdy0/DzwCnALsDrphJoL6YIn+eJ+xT8Bh0taSdJepOs8Uxazmk+Q+uTVer8MXEo68G/LT2Bbkt4iaVfgIuCCiLi7xTK75guRAp4DXs9/LevSof0ljcoH5cnApfljD38lvamxS74ueDywcmW9J4AR6vrd3F8CR+aLu2vw5jWv+V0s31Kuy8XAqZLWzC9GR5GuFy61XJ9LSa3XdUkX8Rst9p+SrjX9E4CkIZK6uhbYnYGkfTcXmC9pZ9KF8U7q9zpwOfA1Savl60tdftYtX9e7DrhM0uaSBkjajnTenBUR90fEQ8A04CRJAyW9l/QC2HApsKuk90oaSDouOs6CiLiWFFLj8qQlOhYk7SWpce3sGdI53e1Hcvr6owX7kpqYc4D/Ab6ad0bDlaTrG8+Q+swfy9cA7iFd57iZdGK9A/hjU9m3AiNJr6SnAntGRLtmb7OzgVG5y3BFZfp5eZuddAevkvQ8qQn+FdK1uK7ebRpJegV9gfTYfhQRN+R53wCOz3X5wmI8hvOBc0nds1WAwyG9awl8lnTd8FFSi6v6ruEl+f9Tkm5vUe45uew/AH8jXTT+z8WoV9V/5u3PIrU8L8zld6rxLmL1b4/K/AuBnYBLmk6iY0ld8FskPUfa9y2vUXUnX9Y4nBS8z5C6npMXo4jxpO7h46Tn6udtlt8DuJ7UhX2BFO5ns/D+/wTpjaenSW86/aJS3xnA50j75bFc54XeMe7At0jvoK/Mkh8LWwO3SnqBtL+OiIi/dbeC2l/TtWb5oub/ARtExHN9XR+z5UVft7CKk7tIRwEXOazMeld//XR0LfJFzCdI74KM6ePqmC133CU0s2K4S2hmxSiuSzho0KAYMWJEX1fDbLkzffr0eRGxfvsl61NcYI0YMYJp06a1X9DMepSk7j6B3yvcJTSzYjiwzKwYDiwzK4YDy8yK4cAys2I4sMysGLUGlqQxku5TGq99kcHolH7OaG4eiO9O9eBPUplZ/1Pb57DygHATSGNQzwamSpqch4apmhQR4+uqh5n1H3W2sLYBZuZxnl8lDVy3e43bM7N+rs5Pug9h4XGqZ5MGFGu2h6T3k0bAPLL510AAlH5yaxzA8OHdjR5ry7oNhw7n8UfbDUNvvWmDIcN4bHZHA+f2uToDq9V41s1DQ1wF/DIiXpF0GGkkzw8uslL6ya2JAKNHj+5oeAmfGMuujY69uq+rYBUPfXPXvq5Cx+oMrNksPLD+UJp+BKJpyOKfkn4nrkc8/ugjPjGWQSWdHLbsqfMa1lRgZB6YfiDp994WGudaC//w6Vjg3hrrY2aFq62FFRHzJY0HrgEGAOdExAxJJwPTIv1s++GSxpJ+Euhp0q/Hmpm1VOvwMvkXbqc0TTuxcvtLpF+JNTNry590N7NiOLDMrBgOLDMrhgPLzIrhwDKzYjiwzKwYDiwzK4YDy8yK4cAys2I4sMysGA4sMyuGA8vMiuHAMrNiOLDMrBgOLDMrhgPLzIrhwDKzYjiwzKwYDiwzK4YDy8yK4cAys2I4sMysGA4sMyuGA8vMiuHAMrNiOLDMrBgOLDMrhgPLzIrhwDKzYjiwzKwYDiwzK4YDy8yKUWtgSRoj6T5JMyUd181ye0oKSaPrrI+Zla22wJI0AJgA7AyMAvaVNKrFcmsChwO31lUXM+sf6mxhbQPMjIhZEfEqcBGwe4vlTgFOB16usS5m1g/UGVhDgEcq92fnaQtIehcwLCKu7q4gSeMkTZM0be7cuT1fUzMrQp2BpRbTYsFMaQXgu8DR7QqKiIkRMToiRq+//vo9WEUzK0mdgTUbGFa5PxSYU7m/JvB24AZJDwLbAZN94d3MulJnYE0FRkraWNJAYB9gcmNmRDwbEYMiYkREjABuAcZGxLQa62RmBastsCJiPjAeuAa4F7g4ImZIOlnS2Lq2a2b914p1Fh4RU4ApTdNO7GLZHeqsi5mVz590N7NiOLDMrBgOLDMrhgPLzIrhwDKzYjiwzKwYDiwzK4YDy8yK4cAys2I4sMysGA4sMyuGA8vMiuHAMrNiOLDMrBgOLDMrhgPLzIrhwDKzYjiwzKwYDiwzK4YDy8yK4cAys2I4sMysGA4sMyuGA8vMiuHAMrNiOLDMrBgOLDMrRkeBJekySbtIcsCZWZ/pNIDOAj4B3C/pNEmb1VgnM7OWOgqsiPhdROwHbAU8CFwr6U+SDpa0Up0VNDNr6LiLJ2k94CDgU8AdwPdJAXZtLTUzM2uyYicLSboc2Aw4H9gtIh7LsyZJmlZX5czMqjoKLOBnETGlOkHSyhHxSkSMrqFeZmaL6LRL+PUW025ut5KkMZLukzRT0nEt5h8m6W5Jd0q6SdKoDutjZsuhbltYkjYAhgCrSnoXoDzrLcBqbdYdAEwAPgTMBqZKmhwR91QWuzAifpyXHwt8BxizJA/EzPq/dl3C/yBdaB9KCpOG54Evt1l3G2BmRMwCkHQRsDuwILAi4rnK8qsD0VGtzWy51G1gRcR5wHmS9oiIyxaz7CHAI5X7s4FtmxeS9DngKGAg8MFWBUkaB4wDGD58+GJWw8z6i3Zdwv0j4gJghKSjmudHxHdarLZg9RbTFmlBRcQEYIKkTwDHAwe2WGYiMBFg9OjRboWZLafadQlXz//XWIKyZwPDKveHAnO6Wf4i0ifqzcxaatcl/En+f9ISlD0VGClpY+BRYB/S13sWkDQyIu7Pd3cB7sfMrAvtuoQ/6G5+RBzezbz5ksYD1wADgHMiYoakk4FpETEZGC9pJ+A14BladAfNzBradQmnL03h+cOmU5qmnVi5fcTSlG9my5dO3iU0M1smtOsSfi8iPi/pKlq/wze2tpqZmTVp1yU8P/8/o+6KmJm1065LOD3/v1HSQNKIDQHcFxGv9kL9zMwW6HR4mV2AHwMPkD4QurGkz0TEr+usnJlZVafDy3wb+EBEzASQ9FbgV4ADy8x6TafDyzzZCKtsFvBkDfUxM+tSu3cJP5ZvzpA0BbiYdA1rL9In2c3Mek27LuFuldtPANvn23OBdWqpkZlZF9q9S3hwb1XEzKydTt8lXAU4FNgcWKUxPSIOqaleZmaL6PSi+/nABqQRSG8kDRXzfF2VMjNrpdPA2jQiTgBezN8v3AV4R33VMjNbVKeB9Vr+/3dJbwfWAkbUUiMzsy50+sHRiZLWAU4AJpNGID2htlqZmbXQUWBFxM/yzRuBTeqrjplZ1zrqEkpaT9KZkm6XNF3S9yStV3flzMyqOr2GdRHpqzh7AHsC84BJdVXKzKyVTq9hrRsRp1Tuf13SR+qokJlZVzptYV0vaR9JK+S/j5NGazAz6zXtvvz8POnLziL9OvMFedYKwAvAV2utnZlZRbvvEq7ZWxUxM2un02tYSBoLvD/fvSEirq6nSmZmrXX6sYbTgCOAe/LfEXmamVmv6bSF9WFgy4h4A0DSecAdwHF1VczMrFmn7xICrF25vVZPV8TMrJ1OW1jfAO6QdD3pHcP3A1+qrVZmZi20DSxJAm4CtgO2JgXWsRHxeM11MzNbSNvAioiQdEVEvJs0UoOZWZ/o9BrWLZK2rrUmZmZtdHoN6wPAYZIeBF4kdQsjIraoq2JmZs06Dayda62FmVkHuu0SSlpF0ueBLwJjgEcj4qHGX7vCJY2RdJ+kmZIW+cyWpKMk3SPpLknXSdpoiR+JmfV77a5hnQeMBu4mtbK+3WnBkgYAE/J6o4B9JY1qWuwOYHTuWl4KnN5p+Wa2/GnXJRwVEe8AkHQ2cNtilL0NMDMiZuX1LwJ2J321B4CIuL6y/C3A/otRvpktZ9q1sBq/lkNEzF/MsocAj1Tuz87TunIo8OtWMySNkzRN0rS5c+cuZjXMrL9o18J6p6Tn8m0Bq+b7jXcJ39LNumoxLVouKO1P6npu32p+REwEJgKMHj26ZRlm1v+1Gw9rwFKUPRsYVrk/FJjTvJCknYCvANtHxCtLsT0z6+cW58vPi2sqMFLSxpIGAvvQ9El5Se8CfgKMjYgna6yLmfUDtQVWvuY1HrgGuBe4OCJmSDo5DwYI8C3Sj7JeIulOSf7qj5l1qeMRR5dEREwBpjRNO7Fye6c6t29m/UudXUIzsx7lwDKzYjiwzKwYDiwzK4YDy8yK4cAys2I4sMysGA4sMyuGA8vMiuHAMrNiOLDMrBgOLDMrhgPLzIrhwDKzYjiwzKwYDiwzK4YDy8yK4cAys2I4sMysGA4sMyuGA8vMiuHAMrNiOLDMrBgOLDMrhgPLzIrhwDKzYjiwzKwYDiwzK4YDy8yK4cAys2I4sMysGA4sMytGrYElaYyk+yTNlHRci/nvl3S7pPmS9qyzLmZWvtoCS9IAYAKwMzAK2FfSqKbFHgYOAi6sqx5m1n+sWGPZ2wAzI2IWgKSLgN2BexoLRMSDed4bNdbDzPqJOruEQ4BHKvdn52mLTdI4SdMkTZs7d26PVM7MylNnYKnFtFiSgiJiYkSMjojR66+//lJWy8xKVWdgzQaGVe4PBebUuD0z6+fqDKypwEhJG0saCOwDTK5xe2bWz9UWWBExHxgPXAPcC1wcETMknSxpLICkrSXNBvYCfiJpRl31MbPy1fkuIRExBZjSNO3Eyu2ppK6imVlb/qS7mRXDgWVmxXBgmVkxHFhmVgwHlpkVw4FlZsVwYJlZMRxYZlYMB5aZFcOBZWbFcGCZWTEcWGZWDAeWmRXDgWVmxXBgmVkxHFhmVgwHlpkVw4FlZsVwYJlZMRxYZlYMB5aZFcOBZWbFcGCZWTEcWGZWDAeWmRXDgWVmxXBgmVkxHFhmVgwHlpkVw4FlZsVwYJlZMRxYZlYMB5aZFaPWwJI0RtJ9kmZKOq7F/JUlTcrzb5U0os76mFnZagssSQOACcDOwChgX0mjmhY7FHgmIjYFvgt8s676mFn56mxhbQPMjIhZEfEqcBGwe9MyuwPn5duXAjtKUo11MrOCrVhj2UOARyr3ZwPbdrVMRMyX9CywHjCvupCkccC4fPcFSfd1UoGHvrnrElR7mTSIpn1Ssn7yvPSr56TDdsJGddejnToDq9UeiCVYhoiYCEzsiUqVSNK0iBjd1/WwN/k56Rt1dglnA8Mq94cCc7paRtKKwFrA0zXWycwKVmdgTQVGStpY0kBgH2By0zKTgQPz7T2B30fEIi0sMzOosUuYr0mNB64BBgDnRMQMSScD0yJiMnA2cL6kmaSW1T511adwy213eBnm56QPyA0aMyuFP+luZsVwYJlZMRxYfUTS65LurPwt8tUl6zuShkq6UtL9kh6Q9P385lHzcjdIWuTjDZIOkvTD3qnt8sOB1XdeiogtK3+n9XWFLMnftrgcuCIiRgJvA9YATu3TipkDa1kiaWdJF1fu7yDpqnz73yXdLOl2SZdIWiNPf1DSSXn63ZI266v69yMfBF6OiJ8DRMTrwJHAIZJWl3SRpLskTQJWbawk6WBJf5V0I/CePql5P+fA6jurNnUJ9wauBbaTtHpeZm9gkqRBwPHAThGxFTANOKpS1rw8/SzgC734GPqrzYHp1QkR8RzwMHA08I+I2ILU4no3gKQNgZNIQfUh0hf+rYfV+dUc695LEbFl80RJvwF2k3QpsAtwDLA96QT4Y/7O10Dg5spql+f/04GP1Vnp5YRo8RWxPH17ctcwIu6SdFeety1wQ0TMBcitr7f1Ql2XKw6sZc8k4HOkD9JOjYjn8zWVayNi3y7WeSX/fx0/pz1hBrBHdYKkt5C+RvYkrcOMbqZbD3GXcNlzA7AV8GlSeAHcArxH0qYAklaT5Ffv+lwHrCbpAFgwttu3gXOB3wD75elvB7bI69wK7CBpPUkrAXv1dqWXBw6svtN8Des0WHCB92rSwIdX52lzgYOAX+YuyC2AL67XJH+f9aPAXpLuB/4KvAx8mXSdcI38PBwD3JbXeQz4Gqmr/jvg9t6vef/nr+aYWTHcwjKzYjiwzKwYDiwzK4YDy8yK4cAys2I4sGwhnY5S0LTOl3urfrZ8c2DZAksxSoEDy3qFA8uquhul4LPV8Z0kXZ1HkziNNz8E+9953gF5NIM/Szo/T9tI0nV5+nWShufp50o6S9L1kmZJ2l7SOZLulXRuZXtdjVZxmqR7crln9NJ+sj7i751ZVctRCiQ9TBfHSkQcJ2l844vckjYHvgK8JyLmSVo3L/pD4BcRcZ6kQ4AfAB/J89YhheVY4CrSiAefAqZK2pL0c3CN0SpelHQscFQO0I8Cm0VESFq7h/aDLaMcWFbV3SgFnX4l4oPApRExDyAiGr8z+W+8OZLE+cDplXWuyoFzN/BERNwNIGkGMIL0m5atRqt4jvSVmZ9J+hX5q0zWfzmwrKq7UQqeZeFLCKt0UUan4VZdpjHaxBuV2437K5JGoWg5WoWkbYAdST8RN54UmNZP+RqWVXU3SsEsYEtJK0gaBmxTWe+1PEJBo4yPS1ovl9HoEv6JN393cj/gpsWoV8vRKvJ1rLUiYgrweWCR8cWsf3ELyxbI3bKPAj+SdALpBW0K6V3AV4G/AXcDf2Hh0QgmAndJuj0i9pN0KnCjpNeBO0gjTRwOnCPpi8Bc4ODFqNdcSQeRRqtYOU8+HngeuFLSKqSW3ZFL9sitFB6twcyK4S6hmRXDgWVmxXBgmVkxHFhmVgwHlpkVw4FlZsVwYJlZMf4fpThgraU1gcwAAAAASUVORK5CYII=\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "# Here are some imports which will be used in code that we write for CS 237\n", "\n", "# IMPORTANT: DO NOT MAKE ANY OTHER IMPORTS WITHOUT DISCUSSING WITH PROFESSOR SNYDER\n", "\n", "# Imports used for the code in CS 237\n", "\n", "import numpy as np # arrays and functions which operate on arrays, plus math functions\n", "import matplotlib.pyplot as plt # normal plotting \n", "import math # You may use the math library if you really want, but\n", " # I recommend you use the numpy library for all mathematical operations.\n", " # Examples of use are in the notebook NumpyTutorial.ipynb on the class web site. \n", "\n", "# We will use these two functions, see note on introduction to lab problems\n", "\n", "from numpy.random import seed, random, randint, choice, shuffle\n", "\n", "from collections import Counter # Essential for creating distributions from experiments\n", " \n", "# This is an improved version of the function from HWs 01 and 02, which allows you to change the\n", "# size and also the labels on the X axis\n", "\n", "def show_distribution(outcomes, title='Probability Distribution', my_xlabels = [], my_figuresize = (8,6)):\n", " plt.figure(figsize=my_figuresize)\n", " num_trials = np.size(outcomes)\n", " X = range( int(min(outcomes)), int(max(outcomes))+1 ) # \n", " freqs = Counter(outcomes)\n", " Y = [freqs[i]/num_trials for i in X]\n", " plt.bar(X,Y,width=1.0,edgecolor='black')\n", " if my_xlabels != []:\n", " plt.xticks(X, my_xlabels)\n", " elif (X[-1] - X[0] < 30):\n", " ticks = range(X[0],X[-1]+1)\n", " plt.xticks(ticks, ticks) \n", " plt.xlabel(\"Outcomes\")\n", " plt.ylabel(\"Probability\")\n", " plt.title(title)\n", " plt.show()\n", " \n", "# Demonstration of the function\n", "dice_rolls = [ (randint(1,7) + randint(1,7)) for k in range(10**3) ] # 1000 rolls of two dice\n", "\n", "show_distribution(dice_rolls, \"Probability Distribution for $10^3$ Dice Rolls\") # notice the Latex in the title!\n", "\n", "show_distribution([ (x % 2) for x in dice_rolls ], \n", " \"Probability Distribution of Even and Odd Rolls\", \n", " my_xlabels=['Even', 'Odd'], my_figuresize=(4,4) )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Analytical Problems Introduction\n", "\n", "\n", "\n", "\n", "### Note on format of numeric answers.\n", "\n", " \n", "The overall principle in writing your answers is to *make the problem easy to grade*! No one benefits from your\n", "work if they can not understand where the answer is or what value is actually being represented. \n", "\n", "There is no need to use Python to do the calculations or formatting for the analytical problems, although\n", "sometimes it is helpful to check your calculations. You can insert a Code cell temporarily somewhere\n", "and type in the expression and cut and paste your answer into the Markdown cell with your solution. \n", "\n", "Here are the guidelines you should follow for the remainder of the course:\n", "\n", "- Quantitative answers must be given as small fractions, or in decimal. Small fractions are fine, as long as they are reduced (no common factors between the numerator and denominator) and not too complicated. So 1/2, 3/8, and 5/32 are fine, but 1215/1944 (= 3/8) is not. \n", "\n", "- Quantitative answers in decimal should be given to 4 significant digits, unless very small, in which case you should give in scientific notation to 4 significant digits (if possible). We're flexible, but don't give an answer 20 digits long!\n", "\n", "- Whenever possible, show your answer in Latex (we'll do more on this later) inside a box, by enclosing it in the syntax:\n", "\n", " $\\boxed{ your answer }$\n", " \n", "for example, \n", "\n", " Here is pi: $\\boxed{3.1416}$.\n", " \n", "Here is pi: $\\boxed{3.1416}$. \n", "\n", "In the next text box are some useful `numpy` functions if you want to use them (not required as long as\n", "you follow the guidelines above). \n", "\n" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Here is the number pi: 3.141592653589793\n", "Here is the number pi rounded to 4 digits: 3.1416\n", "\n", "3.1416\n", "0.0031\n", "0.0\n", "\n", "3.1416e-03\n", "3.1416e-06\n" ] } ], "source": [ "# If you want to round something to 4 digits, you can use the \n", "# function np.around( floating-point number, number-of-significant-digits ):\n", "\n", "print('Here is the number pi:', np.pi)\n", "print('Here is the number pi rounded to 4 digits:', np.around(np.pi,4) )\n", "print()\n", "\n", "# using np.around\n", "print(np.around(np.pi,4)) # this is perfect\n", "print(np.around(np.pi/1000,4)) # this is ok\n", "print(np.around(np.pi/100000,4)) # NOT OK, this returns an inaccurate and unhelpful 0.0\n", "print()\n", "\n", "# using np.format_float_scientific(x,precision=4)\n", "\n", "print( np.format_float_scientific(np.pi/1000,precision=4) )\n", "print( np.format_float_scientific(np.pi/1000000,precision=4) )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Problem 1\n", "\n", "Suppose you roll a single die $n$ times, $n>0$. Give the following probabilities in terms of $n$:\n", "\n", "(A) The number 4 is observed all $n$ times;\n", "\n", "(B) You *never* see the number 4 in any of the $n$ rolls; \n", "\n", "(C) Each of the $n$ rolls shows an even number;\n", "\n", "(D) The $n$ rolls alternate even and odd numbers, starting with even (for example: 2 5 4 1 6 5 ....); \n", "\n", "(E) In the $n$ rolls, each of the numbers 1 and 6 are observed at least once. \n", "\n", "Hint for (E): Use the Inverse Method!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Solution:**\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Problem 2 \n", "\n", "Suppose you roll two fair dice and count the number of dots showing. What is the probability of a sum of 5 if\n", "\n", "(A) the second roll is not 3?\n", "\n", "(B) they land on different numbers?\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Solution:\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Problem 3\n", "\n", "Do problem 23 from the End Of Chapter Problems in Section 1.5." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Solution:**\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Problem 4\n", "\n", "Do problem 24 from the End Of Chapter Problems in Section 1.5." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Solution:**\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Problem 5\n", "\n", "Do problem 25 from the End Of Chapter Problems in Section 1.5." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Solution:**\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Problem 6\n", "\n", "Do problem 34 from the End Of Chapter Problems in Section 1.5." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Solution:**\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Problem 7\n", "\n", "Do problem 35 from the End Of Chapter Problems in Section 1.5." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Solution:**\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Problem 8\n", "\n", "This is a problem about a standard deck of 52 playing cards:\n", "\n", "\n", "\n", "Supposing you shuffle a deck of playing cards thoroughly and draw a single card, give the probability that the card is:\n", "\n", "(A) The King of Diamonds\n", "\n", "(B) A black card \n", "\n", "(C) Not a face card (i.e., not Jack, Queen, King) \n", "\n", "(D) A spade or an Ace \n", "\n", "(E) Neither a black card nor a face card (= \"(not a black card) and (not a face card)\")\n", "\n", "Hint: Remember in D that *or* in English is the \"inclusive or,\" not the \"exclusive or\". " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Solution:**\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Note on choosing randomly\n", "\n", "There are two ways to choose objects from a collection in probability: with replacement and without replacement:\n", "\n", " - **With Replacement**: After an object, such as a playing card, is selected from a collection (such as a deck of cards), it is put back into the collection before the next selection. This is the usual situation when choosing virtual objects such as letter and numbers. In general, the probabilities of various events do not change as objects are chosen, because by putting the object back, you are ensuring that each choice is independent. \n", " \n", " \n", " - **Without Replacement**: After the object is selected, it is NOT put back into the collection. This is the usual situation in card games, where the dealer chooses cards to distribute to the players, and they are given to the players, and not put back in the deck. In general, the probability of events will change, as the sample set is changed by the removal of one object. The choices are NOT independent. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Problem 9\n", "\n", "This is again, a problem about playing cards. We will choose 2 cards with replacement. \n", "\n", "Supposing you shuffle a deck of playing cards thoroughly and draw two cards: you draw the first card, put it *back in the deck*, shuffle it thoroughly and draw a second card. Give the probability that:\n", "\n", "(A) Both cards were face cards;\n", "\n", "(B) The second card was not the exact same card as the first one; \n", "\n", "(C) The two cards were different colors; \n", "\n", "(D) Neither card was a face card; \n", "\n", "(E) If the first card was black, then the second card was red; \n", "\n", "Hint: The probabilities do not change for the second card, since you start all over again with the same\n", "randomized deck. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Solution:**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Problem 10\n", "\n", "Now we will draw two cards without replacement. Suppose you shuffle a deck of playing cards thoroughly and draw the first two cards on the top of the deck (without returning the first card and without shuffling again). Give the probability that\n", "\n", "(A) Both cards were red;\n", "\n", "(B) The first card was red and the second card was a face card; \n", "\n", "(C) The two cards were different colors; \n", "\n", "(D) Neither card was a face card;\n", "\n", "(E) If the first card was black, then the second card was red;\n", "\n", "Hint: The probabilities change, since\n", "you are drawing the second card from a deck with only 51 cards, the first card having been removed. You have to\n", "account for what happened when the first card was removed. A tree diagram, of course, can help, but you don't have to provide it. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Solution:**\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "6D63sUF96D8W" }, "source": [ "## Lab Problems: Shuffling and Choosing from a List\n", "\n", "We will continue to investigate methods for simulating various kinds of random processes, with the same strategy as in the last HW: You will write your own versions of standard functions from the `numpy.random` library: last time you wrote your own versions of `random()` and `randint(...)`; in this lab you will write your own versions of the functions `choice(...)`, and `shuffle(...)`. You may read about them further here, but all the information you need will be presented here, and then we will do some experiments involving a standard deck of 52 playing cards, reproducing experimentally one of the problems you solved analytically above. \n", "\n", "**Important Note:** My educational strategy here is to have you create your own versions of the standard `numpy.random` functions, in order to understand deeply how they work. After that goal is achieved, however, it is better to use the library functions, not your own. The standard library functions are the ones you will use in the future, and in any case they are implemented using state-of-the art random number generators and are the most efficient possible implementations. There is no reason to use your own (presumably less well-implemented) once the goal of understanding is finished. \n", "\n", "Therefore, in this lab, you will use the standard and `randint(...)` . Do NOT use your own `my_randint(...)`. \n", "There is only one difference between your functions and the standard ones, and that is that `numpy` functions in general will work on lists or arrays, applying the function to every member of the list. You should get used to this, and to using list comprehensions, as it leads to much more concise and elegant code, with fewer bugs!" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0.59665541 0.78364425 0.5000263 0.05037006 0.69909807 0.9923964\n", " 0.26726254 0.67909062 0.86428144 0.75084425]\n", "[2 3 2 6 5 6 3 6 6 5]\n" ] } ], "source": [ "# Reminder how these work\n", "\n", "# print out an array of 10 random numbers in range [0..1)\n", "print( random(10))\n", "\n", "# print out an array of 10 random numbers in range [l, ..., 6]\n", "print( randint(1,7,10))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### More Random Functions: Choice and Shuffle\n", "\n", "In more complicated kinds of problems, we need to do more sophisticated things with a collection, such\n", "as when we perform simulations about cards, say if we want to verify the answers to Problems 8 and 9 above. \n", "\n", "There are two useful `numpy.random` functions that we will learn to implement outselves" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Numpy's shuffle function" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[3, 5, 2, 6, 1, 4]" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "die_roll = [1,2,3,4,5,6]\n", "\n", "# Run this cell a few times to see what it does\n", "# Note that it changes the list/array, and does not return a list\n", "\n", "\n", "shuffle( die_roll )\n", "\n", "die_roll" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Numpy's choice function: random sampling\n", "\n", " numpy.random.choice(a, size=None, replace=True)" ] }, { "cell_type": "code", "execution_count": 105, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4\n", "[2 4 6 2 4 4 6 3 1 4 5 1 5 6 4 2 6 4 3 2 5 4 6 6 4]\n", "[3 6 5 1 4]\n" ] } ], "source": [ "# Randomly choose one member of a list or array\n", "\n", "die_roll = [1,2,3,4,5,6]\n", "\n", "print( choice( [1,2,3,4,5,6] ) )\n", "\n", "# Vector version! \n", "\n", "print( choice( [1,2,3,4,5,6], size=25 ) )\n", " \n", "# You can also choose \"without replacement\" (the default is WITH replacement)\n", "\n", "print( choice( [1,2,3,4,5,6], size=5, replace=False))" ] }, { "cell_type": "code", "execution_count": 133, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'d'" ] }, "execution_count": 133, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cards = ['a', 'b', 'c', 'd']\n", "cards\n", "\n", "cards[ randint(len(cards)) ]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "YqAwi1uO6D8Y" }, "source": [ "## Problem 11: Shuffling and Choosing from a List (worth 10 points)\n", "Now we will we will create our own versions of the \n", "shuffle(...) and choice(...) functions, which you can read about\n", "here.\n", "\n", "All you need to do is to demonstrate these as shown. We could test them using probability distributions, but it will sufficient to check the results by eye... You could also test them by comparing\n", "them with the numpy versions, with slight differences as specified\n", "below. The main detail, which I admit is a bit fussy, is\n", "that some numpy functions return a single value by default, \n", "and a list of values if you specify a size. \n", "\n", "NOTE: In this problem, you may use seed(...) and randint(...)from the numpy random library but no other\n", "library functions which generate random results. \n", "\n", "\n", "### (A): Choosing from a list with replacement\n", "\n", "This part is easy: to choose a member of a list randomly and with replacement, simply generate a random integer as an index and return the member at the index. The only small complication is that when size is not specified, it should return a single element; when size is specified, return a list of such randomly-chosen elements. \n" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "colab": {}, "colab_type": "code", "id": "cKTocSYJ6D8a", "outputId": "09e19b54-318c-4466-892d-da61dc7dff19" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Here is one choice: 0\n", "Here are multiple choices:\n", "[]\n", "[]\n", "[]\n", "[]\n", "[]\n", "[]\n", "[]\n", "[]\n", "[]\n", "[]\n" ] } ], "source": [ "# Choose elements from a list with replacement. If size == None, then\n", "# return a single element, else create a list of length size, filled with\n", "# randomly chosen elements from the list \n", "\n", "def choice_with_replacement(X,size=None):\n", " if size == None:\n", " return 0 # your code here\n", " else:\n", " return [ for k in range(size) ]\n", "\n", "# Test it!\n", "\n", "seed(0)\n", "\n", "\n", "X = list(range(1,7))\n", "\n", "print(\"Here is one choice:\", choice_with_replacement(X)) # should be 5\n", "\n", "print(\"Here are multiple choices:\")\n", "for k in range(10):\n", " print(choice_with_replacement(X,size=k)) # last one should be [1, 2, 2, 2, 1, 3, 5, 4, 4]\n" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "HQIwSF_n6D8f" }, "source": [ "### (B): Shuffling a list\n", "\n", "Shuffling a deck of cards means to permute the order sufficientlly that it appears to be random. \n", "One could simply keep exchanging members of the list, but how many such exchanges is necessary?\n", "\n", "A better method is the following, known as the Fisher-Yates Shuffle, which works in $O(n)$. Basically, you maintain a shuffled part of the list and an unshuffled part of the list, and at each step you randomly select an element from the unshuffled part and move it to the shuffled part. \n", "
\n",
    "-- To shuffle an array A of n elements (indices 0..n-1):\n",
    "for i from nāˆ’1 downto 1 do\n",
    "     j ā† random integer such that 0 ā‰¤ j ā‰¤ i\n",
    "     exchange A[j] and A[i]\n",
    "
\n", "Note that this shuffle works in-place. \n", "\n", "Here is a trace of what happens to a list [1,...,10] in \n", "a sample run of the algorithm:\n", "\n", "
\n",
    "i=9 j=5\n",
    "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n",
    "i=8 j=0\n",
    "[1, 2, 3, 4, 5, 10, 7, 8, 9, 6]\n",
    "i=7 j=3\n",
    "[9, 2, 3, 4, 5, 10, 7, 8, 1, 6]\n",
    "i=6 j=3\n",
    "[9, 2, 3, 8, 5, 10, 7, 4, 1, 6]\n",
    "i=5 j=3\n",
    "[9, 2, 3, 7, 5, 10, 8, 4, 1, 6]\n",
    "i=4 j=1\n",
    "[9, 2, 3, 10, 5, 7, 8, 4, 1, 6]\n",
    "i=3 j=3\n",
    "[9, 5, 3, 10, 2, 7, 8, 4, 1, 6]\n",
    "i=2 j=1\n",
    "[9, 5, 3, 10, 2, 7, 8, 4, 1, 6]\n",
    "i=1 j=0\n",
    "[9, 3, 5, 10, 2, 7, 8, 4, 1, 6]\n",
    "
" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "colab": {}, "colab_type": "code", "id": "m1ApeDWm6D8g", "outputId": "db24949a-1051-4666-e2a7-d3fcc0b751b5" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n", "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n", "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n", "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n", "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n" ] } ], "source": [ "# Shuffle using the Fisher-Yates algorithm.\n", "# This will modify the list in place, permanently changing it\n", "\n", "\n", "def my_shuffle(X):\n", " # your code here\n", " pass\n", "\n", "# Test it!\n", "\n", "\n", "seed(0)\n", "\n", "X = [1,2,3,4,5,6,7,8,9,10]\n", "\n", "for k in range(5):\n", " my_shuffle(X) # last one should be [7, 8, 9, 3, 5, 10, 2, 6, 1, 4]\n", " print(X)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "qcGwuckV6D8m" }, "source": [ "### (C) Choosing without replacement from a list\n", "\n", "If you don't care much about efficiency, then to sample WITHOUT replacement (as you do in dealing Poker hands), you should just slice the list produced by shuffling to return a\n", "list of the required length `size`. \n", "\n", "HOWEVER, choice does not change the list, so make sure to make a copy, and shuffle that!\n" ] }, { "cell_type": "code", "execution_count": 139, "metadata": { "colab": {}, "colab_type": "code", "id": "mB8IV93L6D8n", "outputId": "0ed80fd9-3b25-49c7-eef1-7b97db0f19d3" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "None\n", "None\n", "None\n", "None\n", "None\n", "None\n", "None\n", "None\n", "None\n", "None\n", "Here is one choice: None\n" ] } ], "source": [ "# Return a list of length size of elements from the list X; shuffle \n", "# the WHOLE list and slice an initial part of the list and return it.\n", "\n", "# Make a copy of the list, since shuffle will change the this, but this function should NOT change its input. \n", "\n", "\n", "def choice_without_replacement(X,size=None):\n", " X1 = list(X)\n", " # your code here\n", " pass\n", " \n", "# Test it!\n", " \n", "seed(0)\n", " \n", " \n", "X = [1,2,3,4,5,6,7,8,9,10]\n", "for k in range(1,11):\n", " print(choice_without_replacement(X,k)) # last one should be [2, 3, 6, 1, 9, 4, 8, 10, 7, 5]\n", "\n", " \n", "seed(0)\n", "\n", "print(\"Here is one choice:\", choice_without_replacement(X)) # should be 6" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### (D) Bounded Choosing without replacement from a list\n", "\n", "There is one inefficiency in the sampling algorithm using the Fisher-Yates shuffle: it shuffles the whole list, and then only returns a part of the list. With cards, this is exactly what you do, but we might want to think of the most efficient way to do it.\n", "For example, if you are dealing out five cards, you could stop the algorithm after five iterations through the loop (picking only five numbers randomly from the whole deck). \n", "Note that you can't just shuffle part of the list: you have to randomly select numbers from the whole list, making sure you don't choose the same number twice. Stopping the loop early will shuffle only the last part of the list (if you follow the Fisher-Yates algorithm, which works from the back forward through the list). \n", "\n", "Fill in the template below to create a better version of the previous function which does precisely this. \n", "\n" ] }, { "cell_type": "code", "execution_count": 136, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "None\n", "None\n", "None\n", "None\n", "None\n", "None\n", "None\n", "None\n", "None\n", "None\n", "None\n" ] } ], "source": [ "# Return a list of length size of elements from the list X; shuffle \n", "# the list and slice of a part of the list, at the end of the list \n", "\n", "# Make a copy of the list before shuffling it!@\n", "\n", "def bounded_choice_without_replacement(X,size=None):\n", " # your code here\n", " pass\n", "\n", "# Test it! \n", " \n", "seed(0)\n", "\n", "X = [1,2,3,4,5,6,7,8,9,10]\n", "for k in range(1,11):\n", " print(bounded_choice_without_replacement(X,k)) # last one should be [2, 10, 1, 6, 3, 9, 7, 4, 8, 5]\n", "\n", " \n", "seed(0)\n", "\n", "print(\"Here is one choice:\", bounded_choice_without_replacement(X)) # should be a 6" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### (E) Putting it all together: the choice function\n", "\n", "Now, to recreate the functionality of the numpy choice function, we need\n", "to allow the user to select which option, with or without replacement,\n", "that is desired.\n", "\n", "This is trivial, you just need to select the appropriate function you created in (A) or (D). " ] }, { "cell_type": "code", "execution_count": 140, "metadata": { "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "None\n", "None\n", "None\n", "None\n", "None\n", "None\n", "None\n", "None\n", "None\n", "None\n", "\n", "None\n", "None\n", "None\n", "None\n", "None\n", "None\n", "None\n", "None\n", "None\n", "None\n", "Here is one choice: None\n" ] } ], "source": [ "# Choice function with optional parameter to select with or without replacemnt. \n", "# We will depart from the behavior of np.random.choice in one respect: the first\n", "# parameter MUST be a list (numpy allows an integer N to represent the list [0..N-1]).\n", "# We also will not implement the parameter p (the probabilities for the list). \n", "\n", "def my_choice(X,size=None,replace=True):\n", " # your code here\n", " pass\n", " \n", "seed(0)\n", "\n", "X = [1,2,3,4,5,6,7,8,9,10]\n", "for k in range(1,11):\n", " print(my_choice(X,k,True)) # last one should be [4, 3, 8, 3, 1, 1, 5, 6, 6, 7]\n", "\n", "print() \n", "\n", "seed(0)\n", "\n", "X2 = [1,2,3,4,5,6,7,8,9,10]\n", "for k in range(1,11):\n", " print(my_choice(X2,k,False)) # last one should be [2, 10, 1, 6, 3, 9, 7, 4, 8, 5]\n", " \n", "seed(0)\n", "\n", "print(\"Here is one choice:\", my_choice(X)) # should be a 6" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.6" } }, "nbformat": 4, "nbformat_minor": 2 }